GO中使用protobuf,性能和java、rust、c++对比 | 您所在的位置:网站首页 › socket protobuf › GO中使用protobuf,性能和java、rust、c++对比 |
(适用2022年度) 下载protoc程序: tips:由于centos版本过低,只能用protoc-3.0版本,protoc-3.17.0版本用不了 安装protobuf第三方库(这里面包含了proto-go-gen) tips:这里如果安装go之后没有添加goroot路径到bash中的话,那么安装会失败。添加方法: 运行指令打开文件:vi ~/.bashrc 添加下面一行,之后保存,重新登录ssh或者打开终端。 export GOPATH=/home/testgo/go 2022年使用的命令安装protobuf-go,之前的get命令不合适了(注意调整系统时间到正确时间,有可能需要科学上网等): go install google.golang.org/protobuf/cmd/[email protected] 运行命令将proto文件生成go代码: ../protoc3.0/bin/protoc --go_out=golang ./*.proto proto文件生成go代码时候报错:protoc-gen-go: invalid Go import path "." for 解决办法(其中pb为包名): option go_package = "./;pb"; 指定protobuf包版本(此命令会修改go.mod文件): go mod edit -require google.golang.org/[email protected] 如果发生package is not in goroot错误,需要启用module开关(并非是设置成关闭状态,那是老版本了) go代码中引入module的代码如下: import( pb "hello/pb" (此处hello不能没有,否则会报错:package pb is not in GOROOT (/home/testgo/go/src/pb)) proto "google.golang.org/protobuf/proto" (为什么此处不需要hello?) ) 原因是没有启用module开关(GO111MODULE),需要如下目录结构: hello/main.go hello/pb/*.go hello/go.mod 其中需要在hello目录中运行go mod init hello import指令中的引入,需要指定的目录下有go代码文件,否则不能正常引入。 整个测试过程中,使用go版本1.19,性能和java,rust,c++对比如下(其中windows的cpu差点,linux的cpu好点): 解析单个protobuf耗时: go(linux)需要0-2ms; java(linux)需要首次需要48ms,二次需要5-9ms; rust在debug下(windows)需要8ms,在release模式下需要第一次2ms,第二次0ms。 rust在linux下(机器不同),耗时1ms。 c++中(linux)需要1ms。 解析10000个protobuf耗时: go(linux)需要4762ms(关闭gc情况下); java(linux)需要2451ms; rust在debug(windows)模式下需要38294ms,在release模式下需要第一次4031ms,第二次7730ms。 rust在linux下(跟windows不一样)耗时3394ms。 c++(linux)中需要3369ms。 据观察java好像会运用多核性能,也可能是java的垃圾回收器的问题导致,java的cpu使用率会达到140%,go最多100%。 c++代码: 附上rust代码: use std::fs; use protobuf::Message; mod login; mod goods; mod common; mod hero; use crate::login::RoleInfo; extern crate chrono; use chrono::prelude::*; fn main() { println!("Hello, world!"); let bytes = fs::read("e:\\roleinfo.bs").unwrap(); // 这个是迭代器,不是数组 let mut ba = [0u8;34483]; // RUST没法使用动态数组,这里只能写死长度。 for i in 0..bytes.len(){ ba[i] = bytes[i]; } let start = Local::now().timestamp_millis(); let ri = RoleInfo::parse_from_bytes(&ba).unwrap(); print!("name={}, time={}ms\n", ri.get_name(), Local::now().timestamp_millis() - start); let start = Local::now().timestamp_millis(); let ri = RoleInfo::parse_from_bytes(&ba).unwrap(); print!("name={}, time={}ms\n", ri.get_name(), Local::now().timestamp_millis() - start); let start = Local::now().timestamp_millis(); let mut count = 0; while count < 10000{ let ri = RoleInfo::parse_from_bytes(&ba).unwrap(); count = count + 1; } print!("name={}, time={}ms\n", ri.get_name(), Local::now().timestamp_millis() - start); let mut count = 0; while count < 10000{ let ri = RoleInfo::parse_from_bytes(&ba).unwrap(); count = count + 1; } print!("name={}, time={}ms\n", ri.get_name(), Local::now().timestamp_millis() - start); /* protobuf_codegen_pure::Codegen::new() .out_dir("src/protos") .inputs(&["src/protos/common.proto", "src/protos/goods.proto", "src/protos/hero.proto", "src/protos/login.proto"]) .include("src/protos") .run() .expect("Codegen failed."); */ } rust配置Cargo.toml: [package] name = "greeting" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] protobuf-codegen-pure = "2" protobuf="2.5.1" chrono = "0.4" GO代码: package main import "fmt" import "time" import "io/ioutil" import( pb "hello/pb" proto "google.golang.org/protobuf/proto" ) func main() { fmt.Println("Hello, World!") var bs,err=ioutil.ReadFile("./roleinfo.bs") if(err == nil){ fmt.Printf("read success!len=%v \n", len(bs)); } startTime:=time.Now().UnixNano() / 1e6; roleInfo := &pb.RoleInfo{} if err := proto.Unmarshal(bs, roleInfo); err != nil { fmt.Println("Failed to parse address book:", err) } fmt.Println(roleInfo.GetName()); endTime:=time.Now().UnixNano() / 1e6; fmt.Printf("need time: %vms,start=%v end=%v \n", endTime - startTime, startTime, endTime); startTime=time.Now().UnixNano() / 1e6; roleInfo= &pb.RoleInfo{} if err= proto.Unmarshal(bs, roleInfo); err != nil { fmt.Println("Failed to parse address book:", err) } fmt.Println(roleInfo.GetName()); endTime=time.Now().UnixNano() / 1e6; fmt.Printf("need time: %vms,start=%v end=%v \n", endTime - startTime, startTime, endTime); startTime=time.Now().UnixNano() / 1e6; for i:=0; i < 10000; i++{ roleInfo= &pb.RoleInfo{} if err= proto.Unmarshal(bs, roleInfo); err != nil { fmt.Println("Failed to parse address book:", err) } } fmt.Printf("loop end:%s \n", roleInfo.GetName()); endTime=time.Now().UnixNano() / 1e6; fmt.Printf("need time: %vms,start=%v end=%v \n", endTime - startTime, startTime, endTime); startTime=time.Now().UnixNano() / 1e6; for i:=0; i < 10000; i++{ roleInfo= &pb.RoleInfo{} if err= proto.Unmarshal(bs, roleInfo); err != nil { fmt.Println("Failed to parse address book:", err) } } fmt.Printf("loop end 2:%s \n", roleInfo.GetName()); endTime=time.Now().UnixNano() / 1e6; fmt.Printf("need time: %vms,start=%v end=%v \n", endTime - startTime, startTime, endTime); fmt.Println("end!"); } |
CopyRight 2018-2019 实验室设备网 版权所有 |